import { EventEmitter } from "eventemitter3";
import { SelectEvent, SelectMode } from "./eventType";
import { fabric } from "fabric";
import { IPluginOption, PluginClass, PluginTempl } from "./PluginTempl";
import hotkeys from "hotkeys-js";
import { AsyncSeriesHook } from "tapable";

// 生命周期事件类型
export type IEditorHooksType =
  | "hookImportBefore"
  | "hookImportAfter"
  | "hookSaveBefore"
  | "hookSaveAfter"
  | "hookTransform";

class Editor extends EventEmitter {
  [x: string]: any;
  public selectedMode: SelectMode | undefined;
  private canvas: fabric.Canvas | null = null;
  private isDragging: boolean | undefined;
  private lastPosX: number = 0;
  private lastPosY: number = 0;

  // 生命周期函数名
  private hooks: IEditorHooksType[] = [
    "hookImportBefore",
    "hookImportAfter",
    "hookSaveBefore",
    "hookSaveAfter",
    "hookTransform",
  ];
  public hooksEntity: {
    [propName: string]: AsyncSeriesHook<any, any>;
  } = {};

  init(canvas: fabric.Canvas) {
    this.canvas = canvas;
    this.selectedMode = SelectMode.EMPTY;
    this._initSelectEvent();
    this._initActionHooks();
  }

  private _initSelectEvent() {
    this.canvas!.on("selection:created", (e) => this._emitSelectEvent(e));
    this.canvas!.on("selection:updated", (e) => this._emitSelectEvent(e));
    this.canvas!.on("selection:cleared", (e) => this._emitSelectEvent(e));

    this.canvas!.on("mouse:wheel", (opt) => {
      let delta = opt.e.deltaY; // 滚轮向上滚一下是 -100，向下滚一下是 100
      let zoom = this.canvas!.getZoom(); // 获取画布当前缩放值
      console.log(`scale`, opt);
      zoom *= 0.999 ** delta;
      if (zoom > 20) zoom = 20;
      if (zoom < 0.01) zoom = 0.01;
      this.canvas!.setZoom(zoom);
      opt.e.preventDefault();
      opt.e.stopPropagation();

      // let delta = opt.e.deltaY // 滚轮，向上滚一下是 -100，向下滚一下是 100
      // let zoom = canvas.getZoom() // 获取画布当前缩放值
      // zoom *= 0.999 ** delta
      // if (zoom > 20) zoom = 20
      // if (zoom < 0.01) zoom = 0.01
      // canvas.zoomToPoint({ // 关键点
      //   x: opt.e.offsetX,
      //   y: opt.e.offsetY
      //   },
      //   zoom
      // )
      // opt.e.preventDefault()
      // opt.e.stopPropagation()
    });

    // 数遍点击事件
    this.canvas!.on("mouse:down", (opt) => {
      // 鼠标按下时触发

      let evt = opt.e;
      if (evt.altKey === true) {
        // 是否按住alt
        this.isDragging = true; // isDragging 是自定义的
        this.lastPosX = evt.clientX; // lastPosX 是自定义的
        this.lastPosY = evt.clientY; // lastPosY 是自定义的
      } else {
      }
    });

    this.canvas!.on("mouse:move", (opt) => {
      // 鼠标移动时触发
      if (this.isDragging) {
        let evt = opt.e;
        let vpt = this.canvas!.viewportTransform; // 聚焦视图的转换
        vpt![4] += evt.clientX - this.lastPosX;
        vpt![5] += evt.clientY - this.lastPosY;
        this.canvas!.requestRenderAll();
        this.lastPosX = evt.clientX;
        this.lastPosY = evt.clientY;
      }
    });

    this.canvas!.on("mouse:up", (opt) => {
      // 鼠标松开时触发
      console.log(`松开鼠标e`, opt);
      this.canvas!.setViewportTransform(this.canvas!.viewportTransform!); // 设置此画布实例的视口转换
      this.isDragging = false;
    });
  }

  private _emitSelectEvent(e: any) {
    if (!this.canvas) {
      throw TypeError("还未初始化");
    }

    const actives = this.canvas
      .getActiveObjects()
      .filter((item) => !(item instanceof fabric.Line)); // 过滤掉辅助线
    if (actives && actives.length === 1) {
      this.selectedMode = SelectMode.ONE;
      this.emit(SelectEvent.ONE, actives);
    } else if (actives && actives.length > 1) {
      this.selectedMode = SelectMode.MULTI;
      this.emit(SelectEvent.MULTI, actives);
    } else {
      this.emit(SelectEvent.CANCEL);
    }
  }
  get fbCanvas() {
    return this.canvas!;
  }

  // 引入组件
  use(plugin: PluginTempl, options?: IPluginOption) {
    if (this.canvas) {
      // alert(JSON.stringify(plugin));
      const pluginRunTime = new (plugin as PluginClass)(
        this.canvas,
        this,
        options || {}
      );
      this._bindingHooks(pluginRunTime);
      this._bindingHotkeys(pluginRunTime);
      this._bindingApis(pluginRunTime);
    }
    return this;
  }
  destroy() {
    if (this.canvas != null) {
      this.canvas.off("object:selected");
      this.canvas.off("'mouse:down'");
      this.canvas = null;
      this.removeAllListeners();
      this.hooksEntity = {};
    }
  }

  // 绑定hooks方法
  private _bindingHooks(plugin: PluginTempl) {
    this.hooks.forEach((hookName) => {
      const hook = plugin[hookName];
      if (hook) {
        console.log(`this.hooksEntity->`, plugin.pluginName + hookName);
        this.hooksEntity[hookName].tapPromise(
          plugin.pluginName + hookName,
          function () {
            // console.log(hookName, ...arguments);
            // eslint-disable-next-line prefer-rest-params
            const result = hook.apply(plugin, [...arguments]);
            // hook 兼容非 Promise 返回值
            return (result as any) instanceof Promise
              ? result
              : Promise.resolve(result);
          }
        );
      }
    });
  }
  // 绑定快捷键
  private _bindingHotkeys(plugin: PluginTempl) {
    plugin?.hotkeys?.forEach((keyName: string) => {
      // 支持 keyup
      hotkeys(keyName, { keyup: true }, (e) => {
        plugin.hotkeyEvent && plugin.hotkeyEvent(keyName, e);
      });
    });
  }

  // 代理API事件
  private _bindingApis(pluginRunTime: PluginTempl) {
    const { apis = [] } = (pluginRunTime.constructor as any) || {};

    apis.forEach((apiName: string) => {
      this[apiName] = function () {
        // eslint-disable-next-line prefer-rest-params
        return pluginRunTime[apiName].apply(pluginRunTime, [...arguments]);
      };
      console.log(
        `_bindingApis->`,
        `apiName=${apiName},\n pluginRunTime=${this[apiName]}`
      );
    });
  }

  // 生命周期事件
  _initActionHooks() {
    this.hooks.forEach((hookName) => {
      this.hooksEntity[hookName] = new AsyncSeriesHook(["data"]);
    });
  }
  // off(eventName: string, listener: any): this {
  //   return listener ? super.off(eventName, listener) : this;
  // }
}

export default Editor;
